/**
 * Player 
 * Define Player objects
 **/
var Player = function() {

	this.color = 'blue';
	this.position = null;
	this.target = null;
	this.openList = new Array();
	this.closedList = new Array();
	this.lastMove = null;
	this.path = new Array();
	this.bounds = {
		w: 20,
		h: 20
	};

	this.init = function(p) {
		log('*** INIT PLAYER ***');
		this.position = p;
		this.target = this.position;
		this.lastMove = +new Date();
	}

	this.clear = function() {
	}

	this.update = function() {
		this.input();

		if (distance(this.target,this.position) != 0 && interval(this.lastMove, 1))
			this.move();
	}

	this.input = function() {
		input.listen();

		if(input.mouse.click === true) {
			var newTarget = game.mMap.getPosition({x:input.mouse.x,y:input.mouse.y});
			if (game.mMap.isWalkable(newTarget))
				this.setTarget(newTarget);
		}
	}

	this.render = function() {
		if (this.target != null) 
			this.renderTarget();

		var pW = this.getWidth();
		var pH = this.getHeight();
		var pX = this.getDrawX() + (Math.round((game.mMap.getCellWidth() - pW) / 2));
		var pY = this.getDrawY() + + (Math.round((game.mMap.getCellHeight() - pH) / 2));

		CTX.beginPath();
		CTX.rect(pX, pY, pW, pH);
		CTX.fillStyle = this.color;
		CTX.fill();
		CTX.closePath();
	}

	this.renderTarget = function() {
		var pW = this.getWidth();
		var pH = this.getHeight();
		var pX = this.target.x * game.mMap.getCellWidth() + (Math.round((game.mMap.getCellWidth() - pW) / 2));
		var pY = this.target.y * game.mMap.getCellHeight() + (Math.round((game.mMap.getCellHeight() - pH) / 2));

		CTX.beginPath();
		CTX.rect(pX, pY, pW, pH);
		CTX.fillStyle = 'red';
		CTX.fill();
		CTX.closePath();
	}

	this.move = function() {
		this.lastMove = +new Date();
		if (this.path[0] != undefined) {
			// if (distance(this.position,this.path[0].position) < 1.5)
			this.position = this.path[0].position;
			this.path.splice(0,1);
		}
	}

	// Access Configuration
	this.getWidth = function() { return this.bounds.w; }
	this.getHeight = function() { return this.bounds.h; }
	this.getDrawX = function() { return this.position.x * game.mMap.getCellWidth(); }
	this.getDrawY = function() { return this.position.y * game.mMap.getCellHeight(); }
	this.getX = function() { return this.position.x; }
	this.getY = function() { return this.position.y; }

	// A* Pathfinding
	this.setTarget = function(t) {
		if (distance(t,this.target) != 0) {
			this.target = t;
			this.getPath();
		}
	}

	this.getPath = function() {
		// Clean lists
		this.path = [];
		this.openList = [];
		this.closedList = [];
		game.mMap.clear();
		// Player current cell
		var pCell = game.mMap.getCell({x:this.position.x, y:this.position.y});
		this.openList.push(pCell);
		// Boolean to know if we have reached the target
		var reached = false;

		do {
			// 1 - Begin at the starting point A and add it to an “open list” of squares to be considered
			var startCell = this.openList[0];
			startCell.highlight = true;

			// 2 - Drop player current cell from open list
			this.closedList.push(this.openList[0]);
			if (distance(this.openList[0].position, this.position))
				this.path.push(this.openList[0]);
			this.openList.splice(0,1);

			// 3 - Check neighborhood
			var reached = this.checkNeighborhood(startCell);

			// 4 - Sort the list
			this.sortList(this.openList);

			// 5 - Choose a new cell to start
			// startCell.highlight = false;
		} while (!reached && this.closedList.length < game.mMap.getConf().mapSize.w*2);

		if (reached) {
			this.openList[0].highlight = true;
			this.closedList.push(this.openList[0]);
			if (distance(this.openList[0].position, this.position))
				this.path.push(this.openList[0]);
			this.openList.splice(0,1);

			this.cleanPath();
		}
	}

	this.cleanPath = function() {
		// Position : [1, 0] - Bounds : [50x50] - Walkable[G:10 - H:50 - F:60 - Parent:(0,0)]
		// Position : [2, 0] - Bounds : [50x50] - Walkable[G:10 - H:40 - F:50 - Parent:(1,0)]
		// Position : [3, 0] - Bounds : [50x50] - Walkable[G:10 - H:30 - F:40 - Parent:(2,0)]
		// Position : [3, 1] - Bounds : [50x50] - Walkable[G:10 - H:31 - F:41 - Parent:(3,0)]
		// Position : [3, 2] - Bounds : [50x50] - Walkable[G:10 - H:36 - F:46 - Parent:(3,1)]
		// Position : [2, 1] - Bounds : [50x50] - Walkable[G:10 - H:41 - F:51 - Parent:(2,0)]
		// Position : [3, 3] - Bounds : [50x50] - Walkable[G:10 - H:42 - F:52 - Parent:(3,2)]
		// Position : [2, 2] - Bounds : [50x50] - Walkable[G:10 - H:44 - F:54 - Parent:(3,2)]
		// Position : [4, 4] - Bounds : [50x50] - Walkable[G:14 - H:44 - F:58 - Parent:(3,3)]
		// Position : [5, 4] - Bounds : [50x50] - Walkable[G:10 - H:41 - F:51 - Parent:(4,4)]
		// Position : [6, 3] - Bounds : [50x50] - Walkable[G:14 - H:30 - F:44 - Parent:(5,4)]
		// Position : [6, 2] - Bounds : [50x50] - Walkable[G:10 - H:20 - F:30 - Parent:(6,3)]
		// Position : [6, 1] - Bounds : [50x50] - Walkable[G:10 - H:10 - F:20 - Parent:(6,2)]
		// Position : [6, 0] - Bounds : [50x50] - Walkable[G:10 - H:0 - F:10 - Parent:(6,1)] 

		var newPath = [];
		var indexP = this.path[0].path.P.getX()+','+this.path[0].path.P.getY();
		newPath[indexP] = this.path[0];

		for (var i = 1; i < this.path.length; i++) {
			indexP = this.path[i].path.P.getX()+','+this.path[i].path.P.getY();
			if (newPath[indexP] == undefined) {
				newPath[indexP] = this.path[i];
			}
		};

		this.path = [];

		for (x in newPath) {
			this.path.push(newPath[x]);
		}
	}

	this.checkList = function(cell, list) {
		var found = false;
		for (var i = 0; i < list.length; i++) {
			if (distance(list[i].position, cell.position) == 0) {
				found = true;
				break;
			}
		};
		return found;
	}

	this.checkNeighborhood = function(cell) {
		var cX = cell.getX();
		var cY = cell.getY();
		var reached = false;

		for (var i = cX-1; i <= cX+1; i++) {
			for (var j = cY-1; j <= cY+1; j++) {
				if (!(i == cX && j == cY)) {

					checkedCell = game.mMap.getCell({x:i, y:j});

					if ( checkedCell != undefined && checkedCell.isWalkable() && !this.checkList(checkedCell, this.closedList)) {
						if (!this.checkList(checkedCell, this.openList)) {
							this.openList.push(checkedCell);
							// Set G
							checkedCell.path.G = Math.floor(distance(cell.position,checkedCell.position) * 10);
							// checkedCell.path.G = 10;
							// Set H
							checkedCell.path.H = Math.floor(distance(checkedCell.position,this.target) * 10);
							checkedCell.setParent(cell);
						}
						else {
							if (Math.floor(distance(cell.position,checkedCell.position) * 10) < checkedCell.path.G) {
								// Set G
								checkedCell.path.G = Math.floor(distance(cell.position,checkedCell.position) * 10);
								// checkedCell.path.G = 10;
								// Set H
								checkedCell.path.H = Math.floor(distance(checkedCell.position,this.target) * 10);
								checkedCell.setParent(cell);
							}
						}
						if (distance(checkedCell.position, this.target) == 0 && !reached)
							reached = true;
					}
				}

				if (reached)
					break;
			};
			if (reached)
				break;
		};

		return reached;
	}

	// partitionner(tableau T, premier, dernier, pivot)
	// 	échanger T[pivot] et T[dernier]
	// 	j := premier
	// 	pour i de premier à dernier - 1
	// 		si T[i] <= T[dernier] alors
	// 			échanger T[i] et T[j]
	// 			j := j + 1
	// 	échanger T[dernier] et T[j]
	// 	renvoyer j
	this.getSubArray = function(a, first, last, pivot) {
		a.swap(pivot, last);

		var j = first;
		for (var i = first; i < last; i++) {
			if (a[i].getF() <= a[last].getF()) {
				a.swap(i, j);
				j++;
			}
		}

		a.swap(last, j);

		return j;
	}

	// tri_rapide(tableau t, entier premier, entier dernier)
	// 	début
	// 		si premier < dernier alors
	// 			pivot := choix_pivot(t,premier,dernier)
	// 			pivot := partitionner(t,premier, dernier,pivot)
	// 			tri_rapide(t,premier,pivot-1)
	// 			tri_rapide(t,pivot+1,dernier)
	// 		fin si
	// 	fin
	this.quickSort = function(a, first, last) {
		if (first < last) {
			var pivot = Math.round(rand(first, last));
			pivot = this.getSubArray(a, first, last, pivot);
			this.quickSort(a, first, pivot-1);
			this.quickSort(a, pivot+1, last);
		}
	}

	this.sortList = function(list) {
		// Quicksort on list
		this.quickSort(list, 0, list.length-1);
	}
};